package models

import (
	"database/sql"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

func (z *S角色列表) TableName() string {
	return "角色列表"
}

type E角色状态 uint8

const (
	E角色状态_正常     = 0
	E角色状态_NPC    = 1
	E角色状态_摆摊     = 2
	E角色状态_摆摊_准备中 = 2
	E角色状态_仓库     = 3
)

type S角色列表 struct {
	Id         int32           `xorm:"autoincr"` //uid	int
	PlayId     int32           `xorm:"'playid'"`
	V名字        string          `xorm:"'名字'"`
	V种族        string          `xorm:"'种族'"` //人族 Human  精灵 Nephilim
	V性别        bool            `xorm:"'性别'"` //男为1 女为0
	V职业        string          `xorm:"'职业'"` //剑OneHand 斗Bare Blue蓝法 Red红法 弓Bow
	V最后登录时间    time.Time       `xorm:"'最后登录时间'"`
	V行会名       string          `xorm:"'行会名'"`
	V是否城主      bool            `xorm:"'是否城主'"`
	V会长        bool            `xorm:"'会长'"`
	V发型发色      string          `xorm:"'发型发色'"`
	V名字颜色      int             `xorm:"'名字颜色'"`
	V所属地       string          `xorm:"'所属地'"` //Ladianes Veros
	V等级        uint16          `xorm:"'等级'"`
	V当前经验      int64           `xorm:"'当前经验'"`
	V力量        uint16          `xorm:"'力量'"`
	V敏捷        uint16          `xorm:"'敏捷'"`
	V精神        uint16          `xorm:"'精神'"`
	V白魔法       uint16          `xorm:"'白魔法'"`
	V红魔法       uint16          `xorm:"'红魔法'"`
	V蓝魔法       uint16          `xorm:"'蓝魔法'"`
	V黄魔法       uint16          `xorm:"'黄魔法'"`
	V黑魔法       uint16          `xorm:"'黑魔法'"`
	V可分配点数     uint16          `xorm:"'可分配点数'"`
	V移动速度      float32         `xorm:"'移动速度'"`
	V金币        int64           `xorm:"'金币'"`
	V佩戴物品      map[uint8]int32 `xorm:"'佩戴物品'"`
	X          int32           `xorm:"'x'"`
	Y          int32           `xorm:"'y'"`
	Z          int32           `xorm:"'z'"`
	V方向        float32         `xorm:"'方向'"`
	V出生x       int32           `xorm:"'出生地x'"`
	V出生y       int32           `xorm:"'出生地y'"`
	V物理攻击技能栏   string          `xorm:"'物理攻击技能栏'"`
	V物理魔法攻击技能栏 string          `xorm:"'物理魔法攻击技能栏'"`
	V魔法攻击技能栏   string          `xorm:"'魔法攻击技能栏'"`
	V数字栏       map[int]string  `xorm:"'数字栏'"`
	V功能栏       map[int]string  `xorm:"'功能栏'"`
	V背包        S背包列表           `xorm:"'背包'"`   //关联背包
	V红背包       S背包列表           `xorm:"'红背包'"`  //关联背包
	V蓝背包       S背包列表           `xorm:"'蓝背包'"`  //关联背包
	V黄背包       S背包列表           `xorm:"'黄背包'"`  //关联背包
	V任务状态      map[int16]int32 `xorm:"'任务状态'"` //所有的任务状态都在这里面   >0 正常任务 <0每日奖励
	V转生        uint16          `xorm:"'转生'"`
	V寂灭        bool            `xorm:"'寂灭'"` //是否生命十字架消耗完毕
	V状态        E角色状态           `xorm:"-"`    //正常 PK 摆摊 交易 买卖
	V状态内容      interface{}     `xorm:"-"`
	V变身        bool            `xorm:"-"`
	VPK        bool            `xorm:"-"` //是否PK
}
type S摆摊列表 struct {
	V查看角色列表 []int32
	V物品列表   []*S摆摊物品
	V出售金额   int64
}
type S摆摊物品 struct {
	V背包ID uint8
	V摊位X  uint8
	V摊位Y  uint8
	V背包X  uint8
	V背包Y  uint8
	V物品   *Struct物品列表
	V售价   int64
}
type S额外属性 struct {
	V唯一ID  uint16 //
	V技能英文名 string
	V到期时间  time.Time          //什么时间到
	V添加内容  map[uint16]float32 //添加到基本属性里
}

var (
	E位置项链       = uint8(0)
	E位置_头盔      = uint8(1)
	E位置_衣服      = uint8(2)
	E位置_护腿      = uint8(3)
	E位置_左护臂     = uint8(4)
	E位置_右护臂     = uint8(5)
	E位置_左手镯     = uint8(6)
	E位置_右手镯     = uint8(7)
	E位置_武器      = uint8(8)
	E位置_护盾      = uint8(9)
	E位置_左1戒指    = uint8(10)
	E位置_左2戒指    = uint8(11)
	E位置_右1戒指    = uint8(12)
	E位置_右2戒指    = uint8(13)
	E位置_左传声筒    = uint8(14)
	E位置_右传声筒    = uint8(15)
	E位置_左耳环     = uint8(17)
	E位置_右耳环     = uint8(18)
	E位置_上左护身符   = uint8(19)
	E位置_上中护身符   = uint8(20)
	E位置_上右护身符   = uint8(21)
	E位置_下左护身符   = uint8(22)
	E位置_下中护身符   = uint8(23)
	E位置_下右护身符   = uint8(24)
	E位置_腰带      = uint8(26)
	E位置_宠物蛋     = uint8(25)
	E位置_宠物蛋右侧栏位 = uint8(27)
	E位置_斗篷      = uint8(28)
	E位置_斗篷右侧栏位  = uint8(31)
	m_穿戴位置标志    = map[uint8]uint16{
		E位置项链:     0x01,
		E位置_头盔:    0x02,
		E位置_衣服:    0x04,
		E位置_护腿:    0x08,
		E位置_左护臂:   0x10,
		E位置_右护臂:   0x10,
		E位置_左手镯:   0x20,
		E位置_右手镯:   0x20,
		E位置_武器:    0x40,
		E位置_护盾:    0x80,
		E位置_左1戒指:  0x200,
		E位置_左2戒指:  0x200,
		E位置_右1戒指:  0x200,
		E位置_右2戒指:  0x200,
		E位置_左传声筒:  0x0400,
		E位置_右传声筒:  0x0400,
		E位置_左耳环:   0x1000,
		E位置_右耳环:   0x1000,
		E位置_上左护身符: 0x2000,
		E位置_上中护身符: 0x2000,
		E位置_上右护身符: 0x2000,
		E位置_下左护身符: 0x2000,
		E位置_下中护身符: 0x2000,
		E位置_下右护身符: 0x2000,
		/*E位置_腰带      = 24
		E位置_宠物蛋     = 25
		E位置_宠物蛋右侧栏位 = 26
		E位置_斗篷      = 27
		E位置_斗篷右侧栏位  = 28*/
	}
)

func (rt *RunTime) Fun创建角色() bool {
	//初始化rt变量
	rt.V技能列表 = make(map[int32]*Struct技能列表)
	rt.V物品列表 = make(map[int32]*Struct物品列表)
	rt.V位置登记 = make(map[int32]*Struct位置登记)
	角色 := rt.V角色

	属性, ok := m_新角色属性[角色.V职业]
	if ok == false {
		panic("未发现的新角色职业属性:" + 角色.V职业)
	}

	//===========创建对应的背包===============
	角色.V背包.Time = time.Now().Add(time.Hour * 24 * 365)
	角色.V红背包.Time = time.Now().Add(time.Hour * 24 * 365)
	角色.V蓝背包.Time = time.Now().Add(time.Hour * 24 * 365)
	角色.V黄背包.Time = time.Now().Add(time.Hour * 24 * 365)
	角色.V红背包.V类型 = 1
	角色.V蓝背包.V类型 = 2
	角色.V黄背包.V类型 = 3
	if _, err := db.Insert(&角色.V背包); err != nil {
		panic(err)
	}
	if _, err := db.Insert(&角色.V红背包); err != nil {
		panic(err)
	}
	if _, err := db.Insert(&角色.V蓝背包); err != nil {
		panic(err)
	}
	if _, err := db.Insert(&角色.V黄背包); err != nil {
		panic(err)
	}

	角色.V等级 = 属性.V等级
	角色.V可分配点数 = 属性.V可分配点数
	角色.X = 属性.V出生x
	角色.Y = 属性.V出生y
	角色.Z = 0
	角色.V出生x = 属性.V出生x
	角色.V出生y = 属性.V出生y
	角色.V移动速度 = 1
	角色.V金币 = 属性.V金币
	角色.V当前经验 = 属性.V经验

	if _, err := db.Insert(角色); err != nil {
		return false
	}
	rt.Func角色加点(属性.V力量, 属性.V敏捷, 属性.V精神, 属性.V白魔法, 属性.V红魔法, 属性.V蓝魔法, 属性.V黄魔法, 属性.V黑魔法)
	//再次保存背包
	角色.V背包.Uid = 角色.Id
	角色.V红背包.Uid = 角色.Id
	角色.V蓝背包.Uid = 角色.Id
	角色.V黄背包.Uid = 角色.Id
	if _, err := db.Table(角色.V背包).Where("id=?", 角色.V背包.Id).Update(map[string]interface{}{"Uid": 角色.Id}); err != nil {
		panic(err)
	}
	if _, err := db.Table(&角色.V红背包).Where("id=?", 角色.V红背包.Id).Update(map[string]interface{}{"Uid": 角色.Id}); err != nil {
		panic(err)
	}
	if _, err := db.Table(&角色.V蓝背包).Where("id=?", 角色.V蓝背包.Id).Update(map[string]interface{}{"Uid": 角色.Id}); err != nil {
		panic(err)
	}
	if _, err := db.Table(&角色.V黄背包).Where("id=?", 角色.V黄背包.Id).Update(map[string]interface{}{"Uid": 角色.Id}); err != nil {
		panic(err)
	}

	//====================================================
	//分配物品
	小型体力瓶100 := 创建物品(-436)
	小型魔力瓶100 := 创建物品(-435)
	回城卷轴100 := 创建物品(-5)
	回城卷轴100.V数量 = 100
	小型体力瓶100.V数量 = 100
	小型魔力瓶100.V数量 = 100
	if err := rt.背包_存放物品(&角色.V背包, 0, 0, 回城卷轴100); err != nil {
		panic(err)
	}
	if err := rt.背包_存放物品(&角色.V背包, 8, 11, 小型魔力瓶100); err != nil {
		panic(err)
	}
	if err := rt.背包_存放物品(&角色.V背包, 8, 12, 小型体力瓶100); err != nil {
		panic("")
	}
	//===== 分配物品  =============================
	分配物品 := []int32{属性.V衣服, 属性.V头盔, 属性.V武器, 属性.V护盾, 属性.V护腿, 属性.V左护臂, 属性.V右护臂, 属性.V上左护身符, 属性.V上右护身符, 属性.V下左护身符, 属性.V下中护身符, 属性.V下右护身符,
		属性.V左传声筒, 属性.V右传声筒, 属性.V左1戒指, 属性.V左2戒指, 属性.V右1戒指, 属性.V右2戒指, 属性.V项链}
	for _, v := range 分配物品 {
		if v == 0 {
			continue
		}
		wp := 创建物品(v)
		if x, y, ok := rt.背包_查询空位(&角色.V背包, wp); ok == false {
			panic("创建角色都放不到背包里，哪里设置错了?")
		} else {
			rt.背包_存放物品(&角色.V背包, x, y, wp)
		}
	}

	//====================================================
	//全部完成
	return true
}
func (rt *RunTime) 获取角色列表(密码串 string) *Struct用户信息 {
	//发送开始
	rt.AddHeadSend10(0x0A, [][]byte{{}, String2Byte("9400010000000600000048756D616E00000000000000000000000000000000000A0000000800000048616972484D31000900000048616972484D3130000800000048616972484D32000800000048616972484D33000800000048616972484D34000800000048616972484D35000800000048616972484D36000800000048616972484D37000800000048616972484D38000800000048616972484D3900010000000800000046616365484D3100010000000B00000048756E74657253756974000A0000000800000048616972484631000900000048616972484631300008000000486169724846320008000000486169724846330008000000486169724846340008000000486169724846350008000000486169724846360008000000486169724846370008000000486169724846380008000000486169724846390001000000080000004661636548463100010000000B00000048756E74657253756974000000000002000000090000004C616469616E657300060000005665726F7300")})
	用户 := &Struct用户信息{}
	//开始发送用户数据797  超过256字节
	{

		if ok, _ := db.Where("加密串=?", 密码串).Get(用户); ok == false {
			用户 = nil
			panic(fmt.Sprintf("无法搜索到密码串:%s", 密码串))
		}
		//domain := fmt.Sprintf("[PlayId,=,%d]", 用户.Id)
		var jslb []*S角色列表
		if err := db.Where("playid=?", 用户.Id).OrderBy("最后登录时间 DESC").Find(&jslb); err != nil {
			panic(err)
		}
		if len(jslb) == 0 { //没有角色
			tx := CreateBuff(7)
			tx.AddInt16(0x95)
			tx.AddInt32(0)
			rt.AddHeadSend10(0X0A, [][]byte{{}, tx.Buff})
		} else {
			tx := CreateBuff(100)
			tx.AddInt16(0x95)
			tx.AddByte(byte(len(jslb))) //添加个数
			for _, u := range jslb {
				tx.AddStringAndLen(u.V名字)
				tx.AddStringAndLen(u.V种族)
				if u.V性别 == true {
					tx.AddInt32(1)
				} else {
					tx.AddInt32(0)
				}
				tx.AddStringAndLen(u.V职业)
				tx.AddInt32(0x00) //?
				tx.AddInt32(int32(u.V最后登录时间.Add(time.Hour * -8).Unix()))
				tx.AddBytes(String2Byte("0100"))
				tx.AddInt32(0x01000000) //?
				tx.AddInt32(0x00)
				tx.AddStringAndLen(u.V发型发色)
				tx.AddStringAndLen("")
				tx.AddStringAndLen("HunterSuit")
				tx.AddInt32(0x00)
				tx.AddStringAndLen(u.V所属地)
				tx.AddInt32(int32(u.V等级))
				tx.AddInt32(0)
				tx.AddInt32(0)
				tx.AddInt32(0)
				tx.AddInt32(0)
				if u.V佩戴物品 == nil {
					u.V佩戴物品 = make(map[uint8]int32)
				}
				for i := uint8(0); i < 33; i++ {
					v, ok := u.V佩戴物品[i]
					if ok == false {
						tx.AddByte(0)
						continue
					}

					wp := &Struct物品列表{Id: v}
					if ok, _ := db.Get(wp); ok == false {
						tx.AddByte(0)
						continue
					}
					tx.AddByte(01)
					rt.物品_简要信息(tx, wp)
				}
				//tx.AddBytes(String2Byte("0000"))
			}
			rt.AddHeadSend10(0X0A, [][]byte{{}, tx.Buff}) //发送数据
		}
	}
	return 用户
}
func (rt *RunTime) Fun角色退出() bool {
	defer func() {
		m_RunTime.Delete(rt.V角色.V名字) //从全局里删除
	}()
	rt.撤销频道()
	//初始化rt变量

	//==== 保存角色信息  ==================================================================
	m := rt.V角色内容
	if m != nil {
		m.V空间.F删除内容(m.Id)
		rt.V角色.X, rt.V角色.Y = F位置_UE4位置转游戏位置(m.X, m.Y) //同步当前位置
	}
	if _, err := db.Where("id=?", rt.V角色.Id).Update(rt.V角色); err != nil {
		panic(err)
	}
	//==== 保存背包信息  ==================================================================
	for i := uint8(0); i < 4; i++ {
		rt.背包_同步到数据库(rt.背包_获取背包(i))
	}

	//==== 保存角色物品信息  ==================================================================
	for _, v := range rt.V物品列表 {
		if v.Stata.V新建 == true { //新建的，也可能被更新了
			if _, err := db.Insert(v); err != nil {
				fmt.Printf("角色ID:%d  物品编号:%d 错误信息: 无法新建物品,详细信息:%s\r\n", rt.V角色.Id, v.Id, err.Error())
			}
		} else if v.Stata.V修改 == true { //更新的
			var 更新字段 []string
			for k, v := range v.Stata.V更新字段 {
				if v == true {
					continue
				}
				更新字段 = append(更新字段, k)
			}
			if _, err := db.Where("id=?", v.Id).Cols(更新字段...).Update(v); err != nil {
				fmt.Printf("角色ID:%d  物品编号:%d 错误信息: 无法更新到数据库，详细信息:%s\r\n", rt.V角色.Id, v.Id, err.Error())
			}
		}
	}
	//==== 保存角色物品栏信息  ==================================================================
	for _, v := range rt.V技能列表 {
		if v.Stata.V修改 == true {
			var 更新字段 []string
			for k, v := range v.Stata.V更新字段 {
				if v == true {
					continue
				}
				更新字段 = append(更新字段, k)
			}
			if _, err := db.Where("id=?", v.Id).Cols(更新字段...).Update(v); err != nil {
				fmt.Printf("角色ID:%d  技能编号:%d 错误信息: 无法更新到数据库，详细信息:%s\r\n", rt.V角色.Id, v.Id, err.Error())
			}
		}
	}
	return true
}

//功能  人物加点
func (rt *RunTime) Func角色加点(力量 uint16, 敏捷 uint16, 精神 uint16, 白魔法 uint16, 红魔法 uint16, 蓝魔法 uint16, 黄魔法 uint16, 黑魔法 uint16) bool {
	角色 := rt.V角色
	总点数 := 力量 + 敏捷 + 精神 + 白魔法 + 红魔法 + 黑魔法 + 黄魔法 + 蓝魔法
	if 总点数 > 角色.V可分配点数 {
		return false
	}
	角色.V力量 += 力量
	角色.V敏捷 += 敏捷
	角色.V精神 += 精神
	角色.V白魔法 += 白魔法
	角色.V红魔法 += 红魔法
	角色.V黑魔法 += 黑魔法
	角色.V黄魔法 += 黄魔法
	角色.V蓝魔法 += 蓝魔法
	角色.V可分配点数 -= 总点数
	if rt.V角色内容 != nil {
		rt.角色_属性计算(false)
	}
	return rt.技能_检测新技能()
}

func (rt *RunTime) 角色_删除角色(用户 *Struct用户信息, 角色名 string) bool {
	角色 := &S角色列表{}
	if _, err := db.Where("playid=?", 用户.Id).Where("名字=?", 角色名).Delete(角色); err != nil {
		panic(sql.ErrNoRows)
	}
	//由于人物没有登录，所以所有字段肯定没有加载
	//删除所属角色的所有物品
	//删除人物技能
	//删除人物背包
	//删除人物信息
	//删除人物物品栏
	//删除高阶技能
	return true
}
func (rt *RunTime) 角色升级() {
	m := rt.V角色内容
	rt.V角色.V等级++
	rt.V角色.V可分配点数 += 10
	m.V基础属性[E基础属性_当前血量] = m.V基础属性[E基础属性_总血量]
	m.V基础属性[E基础属性_当前蓝量] = m.V基础属性[E基础属性_总蓝量]
	//升级了
	rt.动作_人物升级()
	rt.发送用户信息(用户信息_等级, 用户信息_血量, 用户信息_蓝量, 用户信息_可分配点数, 用户信息_经验值)
	rt.技能_检测新技能()
}

//功能 将物品穿戴到指定位置，并返回被替换下来的装备
//返回
//    bool 是否成功
//    error 失败时的错误信息
//注意 此函数只管穿上，不管被卸下来的装备
func (rt *RunTime) 装备_判断是否可装备(物品 *Struct物品列表, 位置 uint8) error {
	角色 := rt.V角色
	物品信息 := 物品_获取物品信息(物品.V信息ID)
	if 物品信息.V穿戴位置 == 0 {
		return errors.New("不可穿戴")
	}
	//先判断要求是否符合
	switch 角色.V职业 {
	case "OneHand":
		if 物品信息.V职业&0x40 == 0 {
			return errors.New("职业不同")
		}
	case "Bare":
		if 物品信息.V职业&0x20 == 0 {
			return errors.New("职业不同")
		}
	case "Blue":
		if 物品信息.V职业&0x04 == 0 {
			return errors.New("职业不同")
		}
	case "Red":
		if 物品信息.V职业&0x02 == 0 {
			return errors.New("职业不同")
		}
	case "Bow":
		if 物品信息.V职业&0x0200 == 0 {
			return errors.New("职业不同")
		}
	default:
		panic("未知职业")

	}
	for k, v0 := range 物品信息.V属性要求 {
		v := uint16(v0)
		switch k {
		case 0:
			if v > uint16(角色.V等级) {
				return errors.New("等级不符")
			}
		case 1:
			if v > 角色.V力量 {
				return errors.New("力量不符")
			}
		case 2:
			if v > 角色.V敏捷 {
				return errors.New("敏捷不符")
			}
		case 3:
			if v > 角色.V精神 {
				return errors.New("精神不符")
			}
		case 4:
			当前魔法点数 := 角色.V白魔法 + 角色.V红魔法 + 角色.V黑魔法 + 角色.V黄魔法 + 角色.V蓝魔法
			if 当前魔法点数 < v {
				return errors.New("魔法不符")
			}
		case 5:
			if v > 角色.V白魔法 {
				return errors.New("红魔法不符")
			}
		case 6:
			if v > 角色.V红魔法 {
				return errors.New("蓝魔法不符")
			}
		case 7:
			if v > 角色.V蓝魔法 {
				return errors.New("黄魔法不符")
			}
		case 8:
			if v > 角色.V黄魔法 {
				return errors.New("白魔法不符")
			}

		case 9:
			if v > 角色.V黑魔法 {
				return errors.New("黑魔法不符")
			}
		default:
			panic(fmt.Sprintf("未知:%d,%d", k, v))
		}
	}
	//在这里加入，每一转，角色可穿戴的物品可以多一个属性
	属性个数 := 砸宝_获取物品属性个数(物品)
	可最多穿戴属性 := int(rt.V角色.V转生) + 4
	if 属性个数 > 可最多穿戴属性 {
		return errors.New(fmt.Sprintf("您当前%d转,穿戴属性最多%d个", rt.V角色.V转生, 可最多穿戴属性))
	}
	if t, ok := m_穿戴位置标志[位置]; ok == false {
		return errors.New("此位置未定义")
	} else {
		if t != 物品信息.V穿戴位置 {
			return errors.New("此物品不能放置在此位置")
		}
	}
	return nil
}
func (rt *RunTime) 装备_获取指定位置物品(位置 uint8) *Struct物品列表 {
	//var ret *Struct物品列表
	if 物品ID, ok := rt.V角色.V佩戴物品[位置]; ok == false {
		return nil
	} else {
		return rt.V物品列表[物品ID]
	}
}

//功能 将指定装备穿到身上
func (rt *RunTime) 装备_穿着指定位置物品(物品 *Struct物品列表, 位置 uint8) {
	rt.V角色.V佩戴物品[位置] = 物品.Id
}
func (rt *RunTime) 装备_卸载指定位置物品(位置 uint8) {
	delete(rt.V角色.V佩戴物品, 位置)
}

func (rt *RunTime) Func角色登录(用户 *Struct用户信息, 角色名 string) {
	rt.V角色 = &S角色列表{} //先清空选择
	rt.V技能列表 = make(map[int32]*Struct技能列表)
	rt.V物品列表 = make(map[int32]*Struct物品列表)
	rt.V位置登记 = make(map[int32]*Struct位置登记)

	//等待前面退出
	for {
		if oldrt, ok := m_RunTime.Load(rt.V角色.V名字); ok == false {
			if ok, _ := db.Where("playid=?", 用户.Id).Where("名字=?", 角色名).Get(rt.V角色); ok == false {
				panic(sql.ErrNoRows)
			}
			break
		} else {
			oldrt.(*RunTime).tcp.Close()
		}
		time.Sleep(time.Second)
	}
	m_RunTime.Store(rt.V角色.V名字, rt) //保存
	rt.V角色.V最后登录时间 = time.Now()     //设置最后登陆的时间
	//对角色的一些MAP进行初始化
	if rt.V角色.V佩戴物品 == nil {
		rt.V角色.V佩戴物品 = make(map[uint8]int32)
	}
	if rt.V角色.V任务状态 == nil {
		rt.V角色.V任务状态 = make(map[int16]int32)
	}
	{
		if ok, _ := db.Get(&rt.V角色.V背包); ok == false {
			panic(sql.ErrNoRows)
		}
		if ok, _ := db.Get(&rt.V角色.V红背包); ok == false {
			panic(sql.ErrNoRows)
		}
		if ok, _ := db.Get(&rt.V角色.V蓝背包); ok == false {
			panic(sql.ErrNoRows)
		}
		if ok, _ := db.Get(&rt.V角色.V黄背包); ok == false {
			panic(sql.ErrNoRows)
		}
		if rt.V角色.V红背包.V类型 == 0 {
			rt.V角色.V背包.V类型 = 0
			rt.V角色.V背包.Uid = rt.V角色.Id
			rt.V角色.V红背包.V类型 = 1
			rt.V角色.V红背包.Uid = rt.V角色.Id
			rt.V角色.V蓝背包.V类型 = 2
			rt.V角色.V蓝背包.Uid = rt.V角色.Id
			rt.V角色.V黄背包.V类型 = 3
			rt.V角色.V黄背包.Uid = rt.V角色.Id

		}
		for i := uint8(0); i < 4; i++ {
			rt.背包_同步到变量(rt.背包_获取背包(i))
		}
		var jnlb []*Struct技能列表
		if err := db.Where("uid=?", rt.V角色.Id).Find(&jnlb); err != nil {
			panic(err)
		}
		for _, 技能 := range jnlb {
			技能.Stata.V更新字段 = make(map[string]bool)
			rt.V技能列表[技能.V技能ID] = 技能
			//技能.V当前等级属性 = make(map[int]float32) //重新计算技能
			//技能信息 := m_技能信息[技能.V技能ID]
			//rt.F计算属性(技能信息, 技能)
		}

		var wzdj []*Struct位置登记
		if err := db.Where("uid=?", rt.V角色.Id).Find(&wzdj); err != nil {
			panic(err)
		}
		for _, v := range wzdj {
			rt.V位置登记[v.Id] = v
		}

	}
	//rt.消息_底部框显示文字(0, "+-+-+-OFF")
	rt.AddHeadSend10(0x0A, [][]byte{{}, String2Byte("E4000000000000")})
	rt.AddHeadSend10(0x0A, [][]byte{{}, String2Byte("BB00A0460D00")})

	//发送第二笔数据，长度78 含意未知,多次登录,数据一样
	rt.AddHeadSend10(0x0A, [][]byte{{}, String2Byte("C4002E0000000055000000000000005500000000000000640000001100000032392B3020282035352B34393520292000000000000000000000000000")})
	//在地图上添加角色
	fmt.Println("0")
	位置定义 := 位置_获取位置(rt.V角色.X, rt.V角色.Y)
	if 位置定义 != nil {
		if 位置定义.V位置登记 == false {
			rt.V角色.X = rt.V角色.V出生x
			rt.V角色.Y = rt.V角色.V出生y
		}
	}
	坐标X, 坐标Y := F位置_游戏位置转UE4位置(rt.V角色.X, rt.V角色.Y)
	rt.V角色内容 = m_默认空间.F添加内容(E类别_人物, 坐标X, 坐标Y, 0, rt.V角色.V方向, rt.V角色)
	m := rt.V角色内容
	m.V内容附加 = rt
	//发送第四笔数据 包括用户的所有信息

	{
		tx := CreateBuff(100)
		tx.AddInt32(m.Id)
		tx.AddInt16(0x0096)
		tx.AddInt32(0x0129)
		tx.AddInt32(0x0)
		tx.AddStringAndLen(rt.V角色.V名字)
		tx.AddStringAndLen(rt.V角色.V种族)
		tx.AddBool(rt.V角色.V性别)
		tx.AddStringAndLen(rt.V角色.V职业)
		tx.AddInt32(0x02) //1:RC 2:AC
		tx.AddByte(0x00)  //1
		tx.AddStringAndLen("")
		tx.AddStringAndLen("")
		tx.AddStringAndLen("")
		tx.AddStringAndLen(rt.角色_获取行会名称())
		tx.AddStringAndLen("")
		tx.AddStringAndLen(rt.V角色.V发型发色)
		tx.AddStringAndLen("")
		tx.AddStringAndLen("HunterSuit")
		tx.AddInt32(0x07)                  //0
		tx.AddBytes(String2Byte("000100")) //6个
		tx.AddStringAndLen(rt.V角色.V所属地)
		tx.AddInt32(0)
		tx.AddInt32(int32(rt.V角色.V等级))
		tx.AddInt32(0)
		tx.AddInt32(5)
		tx.AddInt64(int64(rt.V角色.V当前经验))
		tx.AddInt64(int64(m_等级经验[rt.V角色.V等级]))
		tx.AddInt32(int32(m.V基础属性[E基础属性_总血量]))
		tx.AddInt32(int32(m.V基础属性[E基础属性_总血量]))
		tx.AddInt32(int32(m.V基础属性[E基础属性_总蓝量]))
		tx.AddInt32(int32(m.V基础属性[E基础属性_总蓝量]))
		tx.AddInt32(int32(rt.V角色.V力量))
		tx.AddInt32(int32(rt.V角色.V敏捷))
		tx.AddInt32(int32(rt.V角色.V精神))
		tx.AddInt32(int32(rt.V角色.V白魔法))
		tx.AddInt32(int32(rt.V角色.V红魔法))
		tx.AddInt32(int32(rt.V角色.V蓝魔法))
		tx.AddInt32(int32(rt.V角色.V黄魔法))
		tx.AddInt32(int32(rt.V角色.V黑魔法))
		tx.AddInt32(int32(rt.V角色.V可分配点数))
		tx.AddInt64(rt.V角色.V金币)
		for wz := uint8(0); wz < 32; wz++ {
			v, ok := rt.V角色.V佩戴物品[wz]
			if ok == false {
				tx.AddByte(0)
				continue
			}
			pds := Fun加载物品([]int32{v}) //加载人物身上的装备
			if len(pds) == 1 {
				rt.V物品列表[pds[0].Id] = pds[0]
				tx.AddByte(1)
				rt.物品_物品信息(tx, pds[0])
			} else {
				delete(rt.V角色.V佩戴物品, wz) //清除没有的装备
				tx.AddByte(0)
			}
		}
		tx.AddInt32(0x00) //		tx.AddBytes(String2Byte("35000000"))
		//开始输出背包
		rt.背包_输出登录信息(tx, &rt.V角色.V背包)
		技能名称 := ""
		//左键技能
		if 技能信息, err := 技能_获取技能信息_英文(rt.V角色.V物理攻击技能栏, rt.V角色.V职业); err == nil {
			技能名称 = 技能信息.V技能英文名
		}
		tx.AddStringAndLen(技能名称)

		//中键技能
		技能名称 = ""
		if 技能信息, err := 技能_获取技能信息_英文(rt.V角色.V物理魔法攻击技能栏, rt.V角色.V职业); err == nil {
			技能名称 = 技能信息.V技能英文名
		}
		tx.AddStringAndLen(技能名称)
		//右键技能
		技能名称 = ""
		if 技能信息, err := 技能_获取技能信息_英文(rt.V角色.V魔法攻击技能栏, rt.V角色.V职业); err == nil {
			技能名称 = 技能信息.V技能英文名
		}
		tx.AddStringAndLen(技能名称)
		if rt.V角色.V数字栏 == nil {
			rt.V角色.V数字栏 = make(map[int]string)
		}
		for i := 0; i < 12; i++ {
			if t, ok := rt.V角色.V数字栏[i]; ok == true {
				sp := strings.Split(t, ":")
				if len(sp) == 2 {
					n, _ := strconv.Atoi(sp[0])
					tx.AddByte(byte(n))
					tx.AddStringAndLen(sp[1])
				} else {
					tx.AddByte(0)
				}

			} else {
				tx.AddByte(0)
			}
		}
		for i := 0; i < 12; i++ {
			tx.AddByte(0)
		}
		if rt.V角色.V功能栏 == nil {
			rt.V角色.V功能栏 = make(map[int]string)
		}
		for i := 0; i < 12; i++ {
			if t, ok := rt.V角色.V功能栏[i]; ok == true {
				sp := strings.Split(t, ":")
				if len(sp) == 2 {
					n, _ := strconv.Atoi(sp[0])
					tx.AddByte(byte(n))
					tx.AddStringAndLen(sp[1])
				} else {
					tx.AddByte(0)
				}
			} else {
				tx.AddByte(0)
			}
		}
		//开始输出角色所属职业的技能信息
		技能信息表 := 技能_获取指定职业技能(rt.V角色.V职业)
		if len(技能信息表) == 0 {
			panic("技能信息表不可能为空,职业名:" + rt.V角色.V职业)
		}
		index := 0
		maxp := len(tx.Buff) //记录最后的位置
		tx.AddByte(0)        //写入技能种类数量
		cnt0 := 0            //技能的种类
		cnt1 := 0            //技能小类中的数量
		minp := 0            //小记长度
		最后技能类型 := ""
		for ; index < len(技能信息表); index++ {
			技能 := 技能信息表[index]
			if 技能.V技能的职业 != rt.V角色.V职业 || 技能.V攻击类型 > 2 {
				tx.Buff[minp] = byte(cnt1) //写入职业内分技能的数量
				tx.Buff[maxp] = byte(cnt0) //写入职业的技能类型数量
				break
			}
			if 技能.V技能类型 != 最后技能类型 {
				cnt0++
				tx.AddStringAndLen(技能.V技能类型)
				if 最后技能类型 != "" {
					tx.Buff[minp] = byte(cnt1)
				}
				minp = len(tx.Buff)
				tx.AddInt32(0)
				最后技能类型 = 技能.V技能类型
				cnt1 = 0
			}
			cnt1++
			输出技能信息(tx, 技能.Id)
		}
		tx.Buff[minp] = byte(cnt1) //写入职业内分技能的数量
		tx.Buff[maxp] = byte(cnt0) //写入职业的技能类型数量
		{
			zwf := len(tx.Buff) //保存点位符
			tx.AddInt32(0)
			已学习数量 := 0
			for k, _ := range rt.V技能列表 {
				技能信息, err := 技能_获取技能信息(k)
				if err != nil {
					continue
				}
				if 技能信息.V攻击类型 > 2 {
					continue
				}
				已学习数量++
				实时技能, _ := rt.技能_获取实时技能列表(技能信息.V技能英文名)
				rt.技能_输出已会技能信息(技能信息, 实时技能, true, tx)
			}
			tx.Buff[zwf] = byte(已学习数量)
			tx.Buff[zwf+1] = byte(已学习数量 >> 8)
		}
		tx.AddBytes(String2Byte("4260853F004002449FB0DC3EB2E7FFFF000000000000000000000000"))
		{
			txp := len(tx.Buff)
			tx.AddInt32(63)
			高阶技能数量 := 0
			for _, v := range 技能信息表 {
				if v.V攻击类型 <= 2 {
					continue
				}
				if v.V攻击类型 >= 10 {
					continue
				}
				if v.V技能的职业 != rt.V角色.V职业 {
					continue
				}
				高阶技能数量++
				rt.输出高阶技能信息(tx, v)
				continue
			}
			tx.Buff[txp] = byte(高阶技能数量)
		}
		tx.AddBytes(String2Byte("0000020000000002000000004E000000"))
		tx.AddBytes(String2Byte("01000000000000000000000000000000000000000000000000000000000000000001000000000100000000"))
		tx.AddInt32(0x00)
		tx.AddInt32(0x03)
		//开始输出背包
		rt.背包_输出登录信息(tx, &rt.V角色.V红背包)
		rt.背包_输出登录信息(tx, &rt.V角色.V蓝背包)
		rt.背包_输出登录信息(tx, &rt.V角色.V黄背包)
		tx.AddBytes(String2Byte("0000000000000000000000000003000000020000000000000000000000"))
		rt.AddHeadSend10(0x04, [][]byte{tx.Buff[:4], tx.Buff[4:]}) //在这里进行最终输出 ,第一个是用户ID，第二个是最终输出
	}
	//设置人物起始地点
	{
		tx := CreateBuff(6 + 4 + 4 + 4)
		tx.AddBytes(String2Byte("25C203000100"))

		坐标X, 坐标Y := F位置_游戏位置转UE4位置(rt.V角色.X, rt.V角色.Y)
		tx.AddInt32(坐标X)
		tx.AddInt32(坐标Y)
		tx.AddInt32(rt.V角色.Z)
		rt.AddHeadSend10(0x07, [][]byte{tx.Buff})
	}
	rt.角色_属性计算(true)
	rt.刷新频道()
	rt.发送系统时间()
	select {
	case val := <-rt.rxchan:
		rt.rxchan <- val //返还数据
	case <-time.After(time.Second * 60):
		panic("")
	}
	rt.背包_同步背包信息()
	m.V准备好 = true

	//判断是否有生命十字架，如果没有，并且未寂灭，则生成十字架
	/*if err := rt.脚本_查询条件("生命十字架", 1); err != nil {
		十字架信息 := m_系统物品列表_中文2["生命十字架"]
		生命十字架 := 创建物品(十字架信息.Id)
		生命十字架.V数量 = 1000 //默认1000次生命
		背包 := rt.背包_获取背包(0)
		x, y, ok := rt.背包_查询空位(背包, 生命十字架)
		if ok == false {
			rt.消息_系统消息(3, "您默认背包中无法放下[生命十字架],请整理后，再登录时重新检测")
		} else {
			rt.背包_存放物品(背包, x, y, 生命十字架)
			rt.同步_背包指定点(背包, x, y, false)
			rt.消息_系统消息(3, "您好，[生命十字架]已放置到默认背包")
		}
	}*/

}
func (rt *RunTime) 刷新频道() {
	m := rt.V角色内容
	传声筒S := []uint8{E位置_左传声筒, E位置_右传声筒}
	for _, 传声筒 := range 传声筒S {
		if 左传声筒ID, ok := rt.V角色.V佩戴物品[传声筒]; ok == true {
			左传声筒 := rt.V物品列表[左传声筒ID]
			sp := strings.Split(左传声筒.V中文名称, "\n")
			if len(sp) == 2 {
				m_电信服务 <- &电信{
					来源: m,
					类型: E挂载频道,
					频道: sp[1],
				}
			}
		}
	}
}
func (rt *RunTime) 撤销频道() {
	m := rt.V角色内容
	传声筒S := []uint8{E位置_左传声筒, E位置_右传声筒}
	for _, 传声筒 := range 传声筒S {
		if 左传声筒ID, ok := rt.V角色.V佩戴物品[传声筒]; ok == true {
			左传声筒 := rt.V物品列表[左传声筒ID]
			sp := strings.Split(左传声筒.V中文名称, "\n")
			if len(sp) == 2 {
				m_电信服务 <- &电信{
					来源: m,
					类型: E撤销频道,
					频道: sp[1],
				}
			}
		}
	}
}

//=============================================================================
//人物的攻击防御等所有属性就是在这里算的

func (rt *RunTime) 角色_属性计算(登陆 bool) {
	m := rt.V角色内容
	原始蓝量 := m.V基础属性[E基础属性_当前蓝量]
	原始血量 := m.V基础属性[E基础属性_当前血量]
	原先增加技能 := make(map[uint16]bool)
	for k, _ := range m.V基础属性 {
		if k > 2000 {
			原先增加技能[k] = true
		}
	}
	m.V基础属性 = make(map[uint16]float32)
	m.V基础属性[E基础属性_移动速度] = rt.V角色.V移动速度 //获取原始角色的移动速度
	// 第一步 获取带封包属性的最终值
	可添加装备 := []uint8{E位置_头盔, E位置_衣服, E位置_护腿, E位置_左护臂, E位置_右护臂, E位置_武器, E位置_护盾}
	for _, v := range 可添加装备 {
		物品ID, ok := rt.V角色.V佩戴物品[v]
		if ok == false || 物品ID == 0 {
			continue
		}
		物品, ok := rt.V物品列表[物品ID]
		if ok == false {
			continue
		}
		if 物品.V当前耐久 <= 0 {
			continue
		}
		物品信息 := 物品_获取物品信息(物品.V信息ID)
		for k, v := range 物品信息.V封包属性 {
			当前值 := m.V基础属性[k]
			当前值 += v
			m.V基础属性[k] = 当前值
		}
	}
	// 第二步 获取所有佩戴物品的附加属性值,放到最终属性里
	for k, v := range rt.V角色.V佩戴物品 {
		物品, ok := rt.V物品列表[v]
		if ok == false || 物品 == nil {
			rt.消息_系统消息(3, fmt.Sprintf("角色佩戴物品不存在,位置:%d,物品ID:%d", k, v))
			delete(rt.V角色.V佩戴物品, k)
			continue
		}
		if len(物品.V附加属性) != 0 {
			for _, 属性行 := range strings.Split(物品.V附加属性, "\n") {
				行分割 := strings.Split(属性行, " ")
				属性等级 := 1
				if len(行分割) == 2 {
					if t, err := strconv.Atoi(行分割[1]); err == nil {
						属性等级 = t
					}
				}
				if 附加属性信息, ok := m_附加属性信息[行分割[0]]; ok == true {
					for kk, vv := range 附加属性信息.V添加到属性 {
						if kk[0] == '#' { //带#表示是技能点
							技能ID := uint16(0)
							if 技能信息, err := 技能_获取技能信息_中文(kk[1:]); err == nil {
								技能ID = uint16(技能信息.Id)
							}
							if 技能ID != 0 {
								技能ID += 2000
								当前值 := m.V基础属性[技能ID]
								当前值 += float32(属性等级) * vv
								m.V基础属性[技能ID] = 当前值
							}
						} else {
							属性ID := m_基础属性[kk]
							if 属性ID != 0 {
								当前值 := m.V基础属性[属性ID]
								当前值 += float32(属性等级) * vv
								m.V基础属性[属性ID] = 当前值
							} else {
								rt.消息_系统消息(3, fmt.Sprintf("物品:%s,未知基础属性名称:%s", 物品.V中文名称, kk))
							}
						}
					}
				} else {
					rt.消息_系统消息(3, fmt.Sprintf("物品:%s,未知属性名称:%s", 物品.V中文名称, 行分割[0]))
				}

			}
		}
	}
	// 第三步 将属性点添加的属性 直接放到最终属性里
	加点提成 := m_角色加点提成[rt.V角色.V职业]
	提成信息 := []map[string]float32{加点提成.V力量, 加点提成.V敏捷, 加点提成.V精神, 加点提成.V白魔法, 加点提成.V红魔法, 加点提成.V蓝魔法, 加点提成.V黄魔法, 加点提成.V黑魔法}
	角色本身属性点 := []uint16{rt.V角色.V力量, rt.V角色.V敏捷, rt.V角色.V精神, rt.V角色.V白魔法, rt.V角色.V红魔法, rt.V角色.V蓝魔法, rt.V角色.V黄魔法, rt.V角色.V黑魔法}
	添加属性点 := []uint16{E基础属性_力量, E基础属性_敏捷, E基础属性_精神, E基础属性_白魔法, E基础属性_红魔法, E基础属性_蓝魔法, E基础属性_黄魔法, E基础属性_黑魔法}
	for i, 提成内容 := range 提成信息 {
		for 基础名称, 基础值 := range 提成内容 {
			属性ID := m_基础属性[基础名称]
			if 属性ID == 0 {
				fmt.Printf("在角色属性点设置中,发现未知名称:%s\r\n", 基础名称)
			} else {
				当前值 := m.V基础属性[属性ID] //获取基础属性中的当前值
				当前值 += 基础值 * float32(角色本身属性点[i]+uint16(m.V基础属性[添加属性点[i]]))
				m.V基础属性[属性ID] = 当前值
			}
		}
	}
	// 第四步 将额外的属性添加到最终属性里
	for _, v := range m.V额外属性 {
		for 属性ID, 添加值 := range v.V添加内容 {
			当前值 := m.V基础属性[属性ID] //获取基础属性中的当前值
			当前值 += 添加值
			m.V基础属性[属性ID] = 当前值
		}
	}
	// 第五步 将地图的额外的属性添加到最终属性里
	if m.V区域 != nil {
		for 属性ID, 添加值 := range m.V区域.V额外属性 {
			当前值 := m.V基础属性[属性ID] //获取基础属性中的当前值
			当前值 += 添加值
			m.V基础属性[属性ID] = 当前值
		}
	}

	//添加 按等级增加物理防御力 功能
	按等级增加物理防御力 := m.V基础属性[E基础属性_按等级增加物理防御力]
	if 按等级增加物理防御力 != 0 {
		物理防御力 := m.V基础属性[E基础属性_物理防御力]
		物理防御力 += 按等级增加物理防御力 * float32(rt.V角色.V等级)
		m.V基础属性[E基础属性_物理防御力] = 物理防御力
	}
	//添加 按等级增加魔法防御力 功能
	按等级增加魔法防御力 := m.V基础属性[E基础属性_按等级增加魔法防御力]
	if 按等级增加物理防御力 != 0 {
		魔法防御力 := m.V基础属性[E基础属性_魔法防御力]
		魔法防御力 += 按等级增加魔法防御力 * float32(rt.V角色.V等级)
		m.V基础属性[E基础属性_魔法防御力] = 魔法防御力
	}
	// 根据以上属性，开始计算所需要的内容
	rt.V物理攻击属性 = make(map[uint16]float32)
	if rt.V角色.V物理攻击技能栏 != "" {
		技能, err := rt.技能_获取实时技能列表(rt.V角色.V物理攻击技能栏)
		if err == nil {
			for k, v := range 技能.V基础属性 {
				rt.V物理攻击属性[k] = v
			}
			//合并基础属性
			for k, v := range m.V基础属性 {
				t := rt.V物理攻击属性[k]
				t += v
				rt.V物理攻击属性[k] = t
			}
		}
	}
	rt.V物理魔法攻击属性 = make(map[uint16]float32)
	if rt.V角色.V物理魔法攻击技能栏 != "" {
		技能, err := rt.技能_获取实时技能列表(rt.V角色.V物理魔法攻击技能栏)
		if err == nil {
			for k, v := range 技能.V基础属性 {
				rt.V物理魔法攻击属性[k] = v
			}
			//合并基础属性
			for k, v := range m.V基础属性 {
				t := rt.V物理魔法攻击属性[k]
				t += v
				rt.V物理魔法攻击属性[k] = t
			}
		}
	}
	rt.V魔法攻击属性 = make(map[uint16]float32)
	if rt.V角色.V魔法攻击技能栏 != "" {
		技能, err := rt.技能_获取实时技能列表(rt.V角色.V魔法攻击技能栏)
		if err == nil {
			for k, v := range 技能.V基础属性 {
				rt.V魔法攻击属性[k] = v
			}
			//合并基础属性
			for k, v := range m.V基础属性 {
				t := rt.V魔法攻击属性[k]
				t += v
				rt.V魔法攻击属性[k] = t
			}
		}
	}
	if 登陆 == true {
		m.V基础属性[E基础属性_当前蓝量] = m.V基础属性[E基础属性_总蓝量]
		m.V基础属性[E基础属性_当前血量] = m.V基础属性[E基础属性_总血量]
	} else {
		m.V基础属性[E基础属性_当前蓝量] = 原始蓝量
		m.V基础属性[E基础属性_当前血量] = 原始血量
	}

	rt.发送用户信息(用户信息_力量,
		用户信息_敏捷,
		用户信息_精神,
		用户信息_可分配点数,
		用户信息_白魔法,
		用户信息_红魔法,
		用户信息_蓝魔法,
		用户信息_黄魔法,
		用户信息_黑魔法,
		用户信息_等级,
		用户信息_经验值,
		用户信息_生命最大值,
		用户信息_魔法最大值,
		用户信息_血量,
		用户信息_蓝量,
		用户信息_攻击力,
		用户信息_第二页)
	for k, _ := range m.V基础属性 {
		if k > 2000 {
			k -= 2000
			if _, ok := rt.V技能列表[int32(k)]; ok == true {
				技能信息, _ := 技能_获取技能信息(int32(k))
				实时技能, _ := rt.技能_获取实时技能列表(技能信息.V技能英文名)
				rt.技能_设置技能等级(技能信息, 实时技能, true) //由于是已会技能，所以这里要加1
				delete(原先增加技能, k)
			}
		}
	}
	for k, _ := range 原先增加技能 {
		if k > 2000 {
			k -= 2000
			if _, ok := rt.V技能列表[int32(k)]; ok == true {
				技能信息, _ := 技能_获取技能信息(int32(k))
				实时技能, _ := rt.技能_获取实时技能列表(技能信息.V技能英文名)
				rt.技能_设置技能等级(技能信息, 实时技能, true) //由于是已会技能，所以这里要加1
			}
		}
	}
}
func (m *StructMap) 周边内容检测() {
	老场景 := make(map[int32]bool)
	if m.V场景 == nil {
		m.V场景 = make(map[int32]bool)
	}
	for k, _ := range m.V场景 {
		老场景[k] = false
	}
	周边内容S := m.V空间.F找到指定位置四周内容(m.X, m.Y, m_可视距离, 0xff)
	for _, v := range 周边内容S {
		if v.Id == m.Id { //自己不算周边内容
			continue
		}
		if _, ok := m.V场景[v.Id]; ok == false { //如果以前没有,则通知用户
			m.V场景[v.Id] = true
			switch m.V类别 {
			case E类别_人物:
				m.V内容附加.(*RunTime).地图_显示内容(v)
			case E类别_怪物: //在发现怪物时，通知怪物
				F地图_发送信息(v, &S交换数据{
					V发送人: m,
					V类型:  E交换数据类型_有人路过,
				})
			}
		} else {
			老场景[v.Id] = true //删除已经有的
		}
	}
	for k, v := range 老场景 {
		if v == true {
			continue
		}
		switch m.V类别 {
		case E类别_人物:
			m.V内容附加.(*RunTime).地图_消失内容(k)
		}
		delete(m.V场景, k)
	}
}

type 用户信息编号 uint8

const (
	用户信息_等级    = 0
	用户信息_经验值   = 1
	用户信息_力量    = 2
	用户信息_敏捷    = 3
	用户信息_精神    = 4
	用户信息_白魔法   = 5
	用户信息_红魔法   = 6
	用户信息_蓝魔法   = 7
	用户信息_黄魔法   = 8
	用户信息_黑魔法   = 9
	用户信息_可分配点数 = 10
	用户信息_血量    = 11
	用户信息_蓝量    = 12
	用户信息_金币    = 13
	用户信息_PK模式  = 14
	用户信息_生命最大值 = 15
	用户信息_魔法最大值 = 16
	用户信息_攻击力   = 17
	用户信息_第二页   = 18
	用户信息_行会    = 19
)

//功能 指定发送的类型给客户端
func (rt *RunTime) 发送用户信息(ids ...用户信息编号) {
	m := rt.V角色内容
	for _, id := range ids {
		tx := CreateBuff(100)
		tx.AddInt16(0x00C4)
		switch id {
		case 用户信息_行会:
			tx.AddByte(0x02)
			tx.AddStringAndLen(rt.角色_获取行会名称())
		case 用户信息_血量:
			tx.AddByte(0x11)
			tx.AddInt32(int32(m.V基础属性[E基础属性_当前血量]))
		case 用户信息_蓝量:
			tx.AddByte(0x12)
			tx.AddInt32(int32(m.V基础属性[E基础属性_当前蓝量]))
		case 用户信息_等级:
			tx.AddByte(0x0A)
			tx.AddInt32(int32(rt.V角色.V等级))
		case 用户信息_经验值:
			tx.AddByte(0x0B)
			tx.AddInt32(0x003E910B)
			tx.AddByte(0x00) //第二次发现不对
			tx.AddInt32(0x00)
			tx.AddInt64(int64(rt.V角色.V当前经验))
			tx.AddInt64(int64(m_等级经验[rt.V角色.V等级]))
		case 用户信息_力量:
			tx.AddByte(0x0C)
			tx.AddInt32(int32(float32(rt.V角色.V力量) + m.V基础属性[E基础属性_力量]))
		case 用户信息_敏捷:
			tx.AddByte(0x0D)
			tx.AddInt32(int32(float32(rt.V角色.V敏捷) + m.V基础属性[E基础属性_敏捷]))
		case 用户信息_精神:
			tx.AddByte(0x0E)
			tx.AddInt32(int32(float32(rt.V角色.V精神) + m.V基础属性[E基础属性_精神]))
		case 用户信息_可分配点数:
			tx.AddByte(0x10)
			tx.AddInt32(int32(rt.V角色.V可分配点数))
		case 用户信息_白魔法:
			tx.AddByte(0x0F)
			tx.AddByte(0x00)
			tx.AddInt32(int32(float32(rt.V角色.V白魔法) + m.V基础属性[E基础属性_白魔法]))
		case 用户信息_红魔法:
			tx.AddByte(0x0F)
			tx.AddByte(0x01)
			tx.AddInt32(int32(float32(rt.V角色.V红魔法) + m.V基础属性[E基础属性_红魔法]))
		case 用户信息_蓝魔法:
			tx.AddByte(0x0F)
			tx.AddByte(0x02)
			tx.AddInt32(int32(float32(rt.V角色.V蓝魔法) + m.V基础属性[E基础属性_蓝魔法]))
		case 用户信息_黄魔法:
			tx.AddByte(0x0F)
			tx.AddByte(0x03)
			tx.AddInt32(int32(float32(rt.V角色.V黄魔法) + m.V基础属性[E基础属性_黄魔法]))
		case 用户信息_黑魔法:
			tx.AddByte(0x0F)
			tx.AddByte(0x04)
			tx.AddInt32(int32(float32(rt.V角色.V黑魔法) + m.V基础属性[E基础属性_黑魔法]))
		case 用户信息_金币:
			tx.AddByte(0x14)
			tx.AddInt64(rt.V角色.V金币)
		case 用户信息_生命最大值:
			tx.AddByte(0x1E)
			tx.AddInt32(int32(m.V基础属性[E基础属性_总血量]))
		case 用户信息_魔法最大值:
			tx.AddByte(0x1F)
			tx.AddInt32(int32(m.V基础属性[E基础属性_总蓝量]))
		case 用户信息_攻击力:
			tx.AddByte(0x2E)
			tx.AddInt32(int32(rt.V物理攻击属性[E基础属性_最小物理攻击力]))
			tx.AddInt32(0x55)
			tx.AddInt32(int32(rt.V物理魔法攻击属性[E基础属性_最小物理攻击力]))
			tx.AddInt32(0x55)
			tx.AddInt32(int32(rt.V魔法攻击属性[E基础属性_最小魔法攻击力]))
			tx.AddInt32(0x64)
			tx.AddStringAndLen(fmt.Sprintf("%d+%d ( %d+%d ) ", int32(m.V基础属性[E基础属性_物理防御力]), int32(m.V基础属性[E基础属性_物理防御千分比]), int32(m.V基础属性[E基础属性_魔法防御力]), int32(m.V基础属性[E基础属性_魔法防御千分比])))
			tx.AddInt32(200)
			tx.AddInt32(int32(m.V基础属性[E基础属性_集中力] / 10))
			tx.AddInt32(int32(m.V基础属性[E基础属性_分散力] / 10))
		case 用户信息_第二页:
			tx = CreateBuff(100)
			tx.AddInt16(0x0085)                              //第二页
			tx.AddFloat(float32(m.V基础属性[E基础属性_格挡成功率]))       //100			tx.AddInt32()
			tx.AddFloat(float32(m.V基础属性[E基础属性_必杀成功率] / 100)) //100
			tx.AddInt32(int32(m.V基础属性[E基础属性_降低对方格挡成功率] / 10))
			tx.AddInt32(int32(m.V基础属性[E基础属性_攻击成功率] / 10)) //这个值是除10的值
			tx.AddInt32(int32(m.V基础属性[E基础属性_生命恢复力]))      //tx.AddInt32()
			tx.AddInt32(int32(m.V基础属性[E基础属性_魔法恢复力]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_全体物品获得率]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_魔法物品获得率]))
			tx.AddFloat(float32(m.V基础属性[E基础属性_攻击速度]))
			tx.AddFloat(float32(m.V基础属性[E基础属性_移动速度]))   //100
			tx.AddInt32(int32(m.V基础属性[E基础属性_亡灵系最大攻击力])) //
			tx.AddInt32(int32(m.V基础属性[E基础属性_生物系最大攻击力])) //tx.AddInt32(m.V基础属性[E基础属性_蓝魔法抵抗力])
			tx.AddInt32(int32(m.V基础属性[E基础属性_召唤系最大攻击力])) //
			tx.AddInt32(int32(m.V基础属性[E基础属性_突变系最大攻击力])) //
			tx.AddInt32(int32(m.V基础属性[E基础属性_人类系最大攻击力]))
			//tx.AddInt32(m.V基础属性[E基础属性_亡灵系最小攻击力])
			tx.AddInt32(int32(m.V基础属性[E基础属性_精灵系最大攻击力]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_亡灵系防御率]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_生物系防御率]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_召唤系防御率])) //tx.AddInt32(m.V基础属性[E基础属性_生物系最小攻击力])
			tx.AddInt32(int32(m.V基础属性[E基础属性_突变系防御率]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_人类系防御率]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_精灵系防御率]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_人类系防御力])) //tx.AddInt32(m.V基础属性[E基础属性_召唤系最小攻击力])
			tx.AddInt32(int32(m.V基础属性[E基础属性_精灵系防御力]))
			tx.AddInt32(2500)
			tx.AddInt32(int32(m.V基础属性[E基础属性_亡灵系防御力]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_生物系防御力])) //tx.AddInt32(m.V基础属性[E基础属性_突变系最小攻击力])
			tx.AddInt32(int32(m.V基础属性[E基础属性_召唤系防御力]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_突变系防御力]))
			tx.AddFloat(float32(m.V基础属性[E基础属性_魔法必杀成功率]))
			tx.AddInt32(3100) //tx.AddInt32(m.V基础属性[E基础属性_人类系最小攻击力])
			tx.AddInt32(3200)
			tx.AddInt32(int32(m.V基础属性[E基础属性_物理反弹]))
			tx.AddInt32(int32(m.V基础属性[E基础属性_魔法反弹]))
			tx.AddInt32(3400) //tx.AddInt32(m.V基础属性[E基础属性_精灵系最小攻击力])
			tx.AddInt32(3500)
			tx.AddInt32(int32(m.V基础属性[E基础属性_魔法抵抗力] / 10))
			tx.AddInt32(int32(m.V基础属性[E基础属性_红魔法抵抗力] / 10))
			tx.AddInt32(0)
			rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})

			tx = CreateBuff(15) //发送当前攻击速度和移动速度
			tx.AddInt16(0x00C4)
			tx.AddByte(0x2D)
			tx.AddFloat(float32(m.V基础属性[E基础属性_移动速度])) //100
			tx.AddFloat(580)
			tx.AddFloat(float32(m.V基础属性[E基础属性_攻击速度]))
			rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
			return
		}
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	}
}
func (rt *RunTime) 同步_角色装备(位置 byte, 同步周边 bool) {
	//取下身上物品
	物品 := rt.装备_获取指定位置物品(位置)
	tx := CreateBuff(50)
	if 物品 == nil {
		tx.AddInt16(0X002D)
		tx.AddByte(位置)
	} else {
		tx.AddInt16(0x002C)
		tx.AddByte(位置)
		rt.物品_物品信息(tx, 物品)
	}
	rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	if 同步周边 == true {
		rt.刷新频道()
		rt.动作_同步角色穿戴装备(位置, 物品)
	}
}

func (rt *RunTime) 角色_处理信息变动(重新计算 bool, 改动参数 map[uint16]bool, 添加技能 []string, 删除技能 []string) {
	m := rt.V角色内容
	for _, 技能名称 := range 删除技能 {
		动作_内容删除辅助技能(m, 技能名称, 10)
	}
	for _, 技能名称 := range 添加技能 {
		动作_内容加辅助技能(m, 技能名称, 10)
	}
	if 重新计算 == true {
		rt.角色_属性计算(false)
	} else {
		改动参数整合 := make(map[用户信息编号]bool)
		for k, _ := range 改动参数 {
			switch k {
			case E基础属性_当前血量:
				改动参数整合[用户信息_血量] = true
			case E基础属性_当前蓝量:
				改动参数整合[用户信息_蓝量] = true
			case E基础属性_等级:
				改动参数整合[用户信息_等级] = true
			case E基础属性_总血量:
				改动参数整合[用户信息_生命最大值] = true
			case E基础属性_总蓝量:
				改动参数整合[用户信息_魔法最大值] = true
			case E基础属性_力量:
				改动参数整合[用户信息_力量] = true
			case E基础属性_敏捷:
				改动参数整合[用户信息_敏捷] = true
			case E基础属性_精神:
				改动参数整合[用户信息_精神] = true
			case E基础属性_白魔法:
				改动参数整合[用户信息_白魔法] = true
			case E基础属性_红魔法:
				改动参数整合[用户信息_红魔法] = true
			case E基础属性_蓝魔法:
				改动参数整合[用户信息_蓝魔法] = true
			case E基础属性_黄魔法:
				改动参数整合[用户信息_黄魔法] = true
			case E基础属性_黑魔法:
				改动参数整合[用户信息_黑魔法] = true
			case E基础属性_总血量:
				改动参数整合[用户信息_生命最大值] = true
			case E基础属性_总蓝量:
				改动参数整合[用户信息_魔法最大值] = true
			case E基础属性_最小物理攻击力, E基础属性_最大物理攻击力,
				E基础属性_最小魔法攻击力, E基础属性_最大魔法攻击力,
				E基础属性_物理防御力, E基础属性_物理防御千分比,
				E基础属性_魔法防御力, E基础属性_魔法防御千分比,
				E基础属性_必杀成功率, E基础属性_魔法必杀成功率,
				E基础属性_格挡成功率, E基础属性_降低对方格挡成功率, E基础属性_攻击成功率,
				E基础属性_集中力, E基础属性_分散力:
				改动参数整合[用户信息_攻击力] = true
			case E基础属性_眩晕, E基础属性_生命恢复力, E基础属性_魔法恢复力, E基础属性_全体物品获得率,
				E基础属性_魔法物品获得率, E基础属性_移动速度,
				E基础属性_魔法抵抗力, E基础属性_红魔法抵抗力, E基础属性_蓝魔法抵抗力, E基础属性_黄魔法抵抗力, E基础属性_物理反弹, E基础属性_魔法反弹,
				E基础属性_攻击速度, E基础属性_亡灵系最小攻击力, E基础属性_亡灵系最大攻击力, E基础属性_亡灵系防御率,
				E基础属性_亡灵系防御力, E基础属性_生物系最小攻击力, E基础属性_生物系最大攻击力, E基础属性_生物系防御率, E基础属性_生物系防御力, E基础属性_召唤系最小攻击力,
				E基础属性_召唤系最大攻击力, E基础属性_召唤系防御率, E基础属性_召唤系防御力, E基础属性_突变系最小攻击力, E基础属性_突变系最大攻击力, E基础属性_突变系防御率,
				E基础属性_突变系防御力, E基础属性_人类系最小攻击力, E基础属性_人类系最大攻击力, E基础属性_人类系防御率, E基础属性_人类系防御力,
				E基础属性_精灵系最小攻击力, E基础属性_精灵系最大攻击力, E基础属性_精灵系防御率, E基础属性_精灵系防御力:
				改动参数整合[用户信息_第二页] = true
			}
			for k, _ := range 改动参数整合 {
				rt.发送用户信息(k)
			}
		}
	}
}
func (rt *RunTime) 角色_是否管理员() bool {
	for _, 管理员 := range strings.Split(GetConfig("系统", "管理员", "GM"), ",") {
		if rt.V角色.V名字 == 管理员 {
			return true
		}
	}
	return false
}
func (rt *RunTime) 角色_获取行会名称() string {
	合成名 := ""
	if rt.V角色.V转生 != 0 {
		合成名 += fmt.Sprintf("%d", rt.V角色.V转生)
	}
	if rt.V角色.V行会名 == "" || strings.Index(rt.V角色.V行会名, "+") != -1 { //无行会或正在申请的，则不显示行会
		if 合成名 != "" {
			合成名 = "---- |" + 合成名
		}
	} else {
		合成名 = rt.V角色.V行会名 + " |" + 合成名
	}
	return 合成名
}
